package com.gismore.demo.config;

import com.gismore.demo.security.StatelessAuthcFilter;
import com.gismore.demo.security.StatelessDefaultSubjectFactory;
import com.gismore.demo.security.StatelessRealm;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.Map;

/**
 * Created by lei on 2017/5/25.
 */
@Configuration
@Slf4j
public class ShiroConfiguration {

	/**
	 * Realm实现
	 * @return
	 */
	@Bean
	public StatelessRealm statelessRealm() {
		StatelessRealm realm = new StatelessRealm();
		return realm;
	}

	/**
	 * Subject工厂
	 * @return
	 */
	@Bean
	public StatelessDefaultSubjectFactory subjectFactory(){
		return new StatelessDefaultSubjectFactory();
	}

	/**
	 * 会话管理器
	 * @return
	 */
	@Bean
	public DefaultSessionManager sessionManager(){
		DefaultSessionManager sessionManager = new DefaultSessionManager();
		sessionManager.setSessionValidationSchedulerEnabled(false);
		return sessionManager;
	}

	/**
	 * 安全管理器
	 * @param statelessRealm
	 * @param subjectFactory
	 * @param sessionManager
	 * @return
	 */
	@Bean
	public DefaultWebSecurityManager securityManager(StatelessRealm statelessRealm,StatelessDefaultSubjectFactory subjectFactory,DefaultSessionManager sessionManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(statelessRealm);
		securityManager.setSubjectFactory(subjectFactory);
		securityManager.setSessionManager(sessionManager);
		DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
		DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator();
		sessionStorageEvaluator.setSessionStorageEnabled(false);
		subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator);
		securityManager.setSubjectDAO(subjectDAO);
		return securityManager;
	}

	/**
	 * 相当于调用SecurityUtils.setSecurityManager(securityManager)
	 * @return
	 */
	@Bean
	public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager securityManager){
		MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
		methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
		methodInvokingFactoryBean.setArguments(new Object[]{securityManager});
		return methodInvokingFactoryBean;
	}

	/**
	 * 每次请求进行认证的拦截器。
	 * @return
	 */
	@Bean
	public StatelessAuthcFilter statelessAuthcFilter(){
		return new StatelessAuthcFilter();
	}

	@Bean
	public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager,StatelessAuthcFilter statelessAuthcFilter){
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		Map<String, Filter> filterMap = Maps.newHashMapWithExpectedSize(1);
		filterMap.put("statelessAuthc", statelessAuthcFilter);
		shiroFilterFactoryBean.setFilters(filterMap);
		shiroFilterFactoryBean.setFilterChainDefinitions(AppConfig.me().filterChainDefinitions());
		return shiroFilterFactoryBean;
	}


	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
		daap.setProxyTargetClass(true);
		return daap;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
		aasa.setSecurityManager(securityManager);
		return aasa;
	}
}
